#include "AssetManager.h"

//==============================
// Constructors / Destructors
//==============================

AssetManager::AssetManager()
	: m_d3dDevice(nullptr), m_GeoFactory(nullptr)
{

}

AssetManager::~AssetManager()
{
	Shutdown();
}

//==============================
// Initialisation Methods
//==============================

void AssetManager::Initialise(ID3D11Device*	d3dDevice)
{
	m_d3dDevice = d3dDevice;
	m_GeoFactory = new GeometryFactory();
	InitMaterials();
	InitMeshes();
}

void AssetManager::InitMeshes()
{
	ID3D11Buffer* m_grid_vb = m_GeoFactory->create_grid_vb(m_d3dDevice, 100.0f, 100.0f, 5, 5);
	ID3D11Buffer* m_grid_ib = m_GeoFactory->create_grid_ib(m_d3dDevice, 100.0f, 100.0f, 5, 5);
	AddBasicMesh(m_grid_vb, m_grid_ib, "Grid");

	//==============================
	// Basic Map Demo
	//==============================

	ModelData* HighResCube = new ModelData(m_d3dDevice, "character-controller/content/models/highres_cube.txt");
	ModelData* HighResCylinder = new ModelData(m_d3dDevice, "character-controller/content/models/highres_cylinder.txt");

	AddModel("HighResCube", HighResCube);
	AddModel("HighResCylinder", HighResCylinder);

	InstanceMap* CubeInstanceMap = new InstanceMap(m_d3dDevice, "highcube", "character-controller/content/maps/map.txt");
	InstanceMap* CylinderInstanceMap = new InstanceMap(m_d3dDevice, "highcylinder", "character-controller/content/maps/map.txt");

	AddInstanceMap("HighResCubes", CubeInstanceMap);
	AddInstanceMap("HighResCylinders", CylinderInstanceMap);

	//==============================
	// Large Map Demo
	//==============================
/*
	// Create VB / IB / AABB / CPU Model Data for each model in level.

	ModelData* Block01		= new ModelData(m_d3dDevice,"character-controller/content/models/block01.txt");
	ModelData* Building01	= new ModelData(m_d3dDevice,"character-controller/content/models/building01.txt");
	ModelData* Building02	= new ModelData(m_d3dDevice,"character-controller/content/models/building02.txt");
	ModelData* Building03	= new ModelData(m_d3dDevice,"character-controller/content/models/building03.txt");
	ModelData* Building04	= new ModelData(m_d3dDevice,"character-controller/content/models/building04.txt");
	ModelData* Pole01		= new ModelData(m_d3dDevice,"character-controller/content/models/pole01.txt");
	ModelData* Pole02		= new ModelData(m_d3dDevice,"character-controller/content/models/pole02.txt");

	// Add models to model vector.

	AddModel("Block01",		Block01);
	AddModel("Building01",	Building01);
	AddModel("Building02",	Building02);
	AddModel("Building03",	Building03);
	AddModel("Building04",	Building04);
	AddModel("Pole01",		Pole01);
	AddModel("Pole02",		Pole02);

	// Create an instance map for each model by reading from the map.txt file.

	InstanceMap* Block01InstanceMap		= new InstanceMap(m_d3dDevice, "block01", "character-controller/content/maps/map_demo.txt");
	InstanceMap* Building01InstanceMap	= new InstanceMap(m_d3dDevice, "building01", "character-controller/content/maps/map_demo.txt");
	InstanceMap* Building02InstanceMap	= new InstanceMap(m_d3dDevice, "building02", "character-controller/content/maps/map_demo.txt");
	InstanceMap* Building03InstanceMap	= new InstanceMap(m_d3dDevice, "building03", "character-controller/content/maps/map_demo.txt");
	InstanceMap* Building04InstanceMap	= new InstanceMap(m_d3dDevice, "building04", "character-controller/content/maps/map_demo.txt");
	InstanceMap* Pole01InstanceMap		= new InstanceMap(m_d3dDevice, "pole01", "character-controller/content/maps/map_demo.txt");
	InstanceMap* Pole02InstanceMap		= new InstanceMap(m_d3dDevice, "pole02", "character-controller/content/maps/map_demo.txt");

	// Add instance maps to the instance maps vector.

	AddInstanceMap("Blocks01",		Block01InstanceMap);
	AddInstanceMap("Buildings01",	Building01InstanceMap);
	AddInstanceMap("Buildings02",	Building02InstanceMap);
	AddInstanceMap("Buildings03",	Building03InstanceMap);
	AddInstanceMap("Buildings04",	Building04InstanceMap);
	AddInstanceMap("Poles01",		Pole01InstanceMap);
	AddInstanceMap("Poles02",		Pole02InstanceMap);
*/
}

void AssetManager::InitMaterials()
{
	Material grid_mat;
	Material box_mat;

	// Create materials and diffuse maps.
	grid_mat.Diffuse  = XMFLOAT4(0.8f, 0.8f, 0.8f, 1.0f);
	grid_mat.Ambient  = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
	grid_mat.Specular = XMFLOAT4(0.1f, 0.1f, 0.1f, 1.0f);

	box_mat.Diffuse  = XMFLOAT4(0.4f, 0.4f, 0.4f, 1.0f);
	box_mat.Ambient  = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
	box_mat.Specular = XMFLOAT4(0.1f, 0.1f, 0.1f, 1.0f);

	AddMaterial("Grid", grid_mat);
	AddMaterial("Box", box_mat);
}

//==============================
// Player Mesh Methods
//==============================

ID3D11Buffer* AssetManager::CreatePlayerVertexBuffer(ID3D11Device* md3dDevice)
{
	ID3D11Buffer* cylinder_vb = m_GeoFactory->create_cylinder_vb(md3dDevice, 0.25, 0.25, 1, 16, 16);
	return cylinder_vb;	
}
	
ID3D11Buffer* AssetManager::CreatePlayerIndexBuffer(ID3D11Device* md3dDevice)
{
	ID3D11Buffer* cylinder_ib = m_GeoFactory->create_cylinder_ib(md3dDevice, 0.25, 0.25, 1, 16, 16);
	return cylinder_ib;
}

//==============================
// Add to Container Methods
//==============================

void AssetManager::AddMaterial(std::string name, Material& material)
{
	m_mapMaterials.insert(std::pair<std::string, Material&> (name, material) );
}

void AssetManager::AddModel(std::string name, ModelData* model)
{
	m_mapModels.insert(std::pair<std::string, ModelData*> (name, model) );
}

void AssetManager::AddInstanceMap(std::string name, InstanceMap* instanceMap)
{
	m_mapInstances.insert(std::pair<std::string, InstanceMap*> (name, instanceMap) );
}

void AssetManager::AddBasicMesh(ID3D11Buffer* vb, ID3D11Buffer* ib, std::string Material)
{
	m_vecMeshes.push_back(new BasicMesh(vb, ib, GetMaterial(Material), NULL, false));
}

//==============================
// Get from Container Methods
//==============================

void AssetManager::GetInstanceMaps(std::vector<InstanceMap*>& vecInstanceMaps)
{
	std::map<std::string, InstanceMap*>::iterator it = m_mapInstances.begin();

	for(it; it != m_mapInstances.end(); ++it)
	{
		vecInstanceMaps.push_back(it->second);
	}
}

void AssetManager::GetModelData(std::vector<ModelData*>& vecModelData)
{
	std::map<std::string, ModelData*>::iterator it = m_mapModels.begin();

	for(it; it != m_mapModels.end(); ++it)
	{
		vecModelData.push_back(it->second);
	}
}

std::vector<IMesh*>* AssetManager::GetBasicMeshes()
{
	return &m_vecMeshes;
}

InstanceMap* AssetManager::GetInstanceMap(std::string name)
{
	std::map<std::string, InstanceMap*>::iterator it;

	it = m_mapInstances.find(name);
	
	if(it != m_mapInstances.end() )
	{
		return it->second;
	}
	else	
	{
		MessageBox(NULL, L"Failed to find Instance Map.", L"Asset Manager Error", MB_OK);
		return nullptr;
	}
}

ModelData* AssetManager::GetModelData(std::string name)
{
	std::map<std::string, ModelData*>::iterator it;

	it = m_mapModels.find(name);
	
	if(it != m_mapModels.end() )
	{
		return it->second;
	}
	else	
	{
		MessageBox(NULL, L"Failed to find Model Data.", L"Asset Manager Error", MB_OK);
		return nullptr;
	}
}

Material* AssetManager::GetMaterial(std::string material)
{
	std::map<std::string, Material>::iterator it;

	it = m_mapMaterials.find(material);
	
	if(it != m_mapMaterials.end() )
	{
		return &it->second;
	}
	else	
	{
		MessageBox(NULL, L"Failed to find Material.", L"Asset Manager Error", MB_OK);
		return nullptr;
	}
}

//==============================
// Shutdown Methods
//==============================

void AssetManager::Shutdown()
{
	DeleteAssets();
	SafeDelete(m_GeoFactory);
}

void AssetManager::DeleteAssets()
{
	// Delete Meshes

	std::vector<IMesh*>::iterator itmesh = m_vecMeshes.begin();

	while(itmesh != m_vecMeshes.end() )
	{
		itmesh = m_vecMeshes.erase(itmesh);
	}

	// Delete Materials

	std::map<std::string, Material>::iterator itmat = m_mapMaterials.begin();

	while( itmat != m_mapMaterials.end() )
	{
		itmat = m_mapMaterials.erase(itmat);
	}

	// Delete Instance Maps

	std::map<std::string, InstanceMap*>::iterator itIM = m_mapInstances.begin();

	while( itIM != m_mapInstances.end() )
	{
		itIM = m_mapInstances.erase(itIM);
	}

	// Delete Model Data

	std::map<std::string, ModelData*>::iterator itMD = m_mapModels.begin();

	while( itMD != m_mapModels.end() )
	{
		itMD = m_mapModels.erase(itMD);
	}
}
